/********************************************************************
	created:	2008/10/06
	created:	6:10:2008   22:47
	filename: 	h:\SimoneEngine\qianye\src\qylib\math\qyColor.h
	author:		Xiong Jiayu
	copyright:  
	purpose:	
*********************************************************************/
#pragma once

#ifndef __QYCOLOR_H__
#define __QYCOLOR_H__

#include "../common/qyCommon.h"

/*
===========================================
struct qyColor
===========================================
*/
struct qyColor
{
	float				r, g, b, a;

						qyColor();
						qyColor( const qyColor &c );
						qyColor( const float val_r, const float val_g, const float val_b, const float val_a );
    
    void                Set( const float val_r, const float val_g, const float val_b, const float val_a );
    uint32_t            To_A8_R8_G8_B8( void ) const;
    void                From_A8_R8_G8_B8( uint32_t &color );
    
    void                AddValue( const float val_r, const float val_g, const float val_b, const float val_a );
    void                BlendWith( const qyColor &dest, const float destAlpha );
    void                ColorStandard();
    float               Normalize();
    float               NormalizeFast();

    qyColor &           operator=( const qyColor &another );
    qyColor &           operator+=( const qyColor &another );
    qyColor             operator*( const float scale ) const;
	float				operator[]( const int index ) const;
	float &				operator[]( const int index );

	bool				Compare( const qyColor &another ) const;
	bool				Compare( const qyColor &another, const float epsilon ) const;
};
const float inv_color_pack = 1 / 255.0f;

//-----------------------------------------------------------------------
QY_INLINE qyColor::qyColor( void )
: r( 1.0f )
, g( 1.0f )
, b( 1.0f )
, a( 1.0f )
{
}

//-----------------------------------------------------------------------
QY_INLINE qyColor::qyColor( const qyColor &c )
: r( c.r )
, g( c.g )
, b( c.b )
, a( c.a )
{
}

//-----------------------------------------------------------------------
QY_INLINE qyColor::qyColor( const float val_r, const float val_g, const float val_b, const float val_a )
: r( val_r )
, g( val_g )
, b( val_b )
, a( val_a )
{
}

//-----------------------------------------------------------------------
QY_INLINE void qyColor::Set( const float val_r, const float val_g, const float val_b, const float val_a )
{
    r = val_r; g = val_g; b = val_b; a = val_a;
}

//-----------------------------------------------------------------------
QY_INLINE qyColor & qyColor::operator =( const qyColor &another )
{
    r = another.r; g = another.g; b = another.b; a = another.a;
    return (*this);
}

//-----------------------------------------------------------------------
QY_INLINE qyColor qyColor::operator *( const float scale ) const
{
    return qyColor( r * scale, g * scale, b * scale, a * scale );
}

//-----------------------------------------------------------------------
QY_INLINE qyColor & qyColor::operator +=( const qyColor &another )
{
    a += another.a;
    r += another.r;
    g += another.g;
    b += another.b;
    return (*this);
}

//-----------------------------------------------------------------------
QY_INLINE uint32_t qyColor::To_A8_R8_G8_B8() const
{
    return ( 
        ((((uint32_t)(r*255.f) ) & 0xff )<< 16 ) |
        ((((uint32_t)(g*255.f) ) & 0xff )<< 8 )  |
        (((uint32_t)(b*255.f) ) & 0xff )         |
        ((((uint32_t)(a*255.f) ) & 0xff )<< 24 )
        );
}

//-----------------------------------------------------------------------
QY_INLINE void qyColor::From_A8_R8_G8_B8( uint32_t &color )
{
    r = (( color & 0x00ff0000 ) >> 16 ) * inv_color_pack;
    g = (( color & 0x0000ff00 ) >> 8 ) * inv_color_pack;
    b = (( color & 0x000000ff ) ) * inv_color_pack;
    a = (( color & 0xff000000 ) >> 24 )  * inv_color_pack;
}

//-----------------------------------------------------------------------
QY_INLINE void qyColor::AddValue( const float val_r, const float val_g, const float val_b, const float val_a )
{
    r += val_r;
    g += val_g;
    b += val_b;
    a += val_a;
}

//-----------------------------------------------------------------------
QY_INLINE void qyColor::ColorStandard()
{
    if ( r > 1 )
    {
        r = 1;
    }
    else if ( r < 0 )
    {
        r = 0;
    }
    
    if ( g > 1 )
    {
        g = 1;
    }
    else if ( g < 0 )
    {
        g = 0;
    }
    
    if ( b > 1 )
    {
        b = 1;
    }
    else if ( b < 0 )
    {
        b = 0;
    }
    
    if ( a > 1 )
    {
        a = 1;
    }
    else if ( a < 0 )
    {
        a = 0;
    }
    
    /*
    a = a > 0 ? a : 0;
    r = r > 0 ? r : 0;
    g = g > 0 ? g : 0;
    b = b > 0 ? b : 0;
    a = a > 1 ? 1 : a;
    r = r > 1 ? 1 : r;
    g = g > 1 ? 1 : g;
    b = b > 1 ? 1 : b;
    */
}

//-----------------------------------------------------------------------
QY_INLINE void qyColor::BlendWith( const qyColor &dest, const float destAlpha )
{
    if ( destAlpha >= 1 )
    {
        (*this) = dest;
    }
    else if ( destAlpha <= 0)
    {
        return;
    }
    float srcAlpha = 1.0f - destAlpha;
    srcAlpha = srcAlpha > 0 ? srcAlpha : 0;
    r = r * srcAlpha + dest.r * destAlpha;
    g = g * srcAlpha + dest.g * destAlpha;
    b = b * srcAlpha + dest.b * destAlpha;
    a = a * srcAlpha + dest.a * destAlpha;
}

//-----------------------------------------------------------------------
QY_INLINE float qyColor::Normalize()
{
    float sqrLength, invLength;

    sqrLength = r * r + g * g + b * b + a * a;

    if ( !sqrLength ) {		
        return 0.0f;
    }

    invLength = 1.0f / ( sqrtf( sqrLength ) );
    r *= invLength;
    g *= invLength;
    b *= invLength;
    a *= invLength;
    return invLength * sqrLength;
}

//-----------------------------------------------------------------------
QY_INLINE float qyColor::NormalizeFast()
{
    float sqrLength, invLength;

    sqrLength = r * r + g * g + b * b + a * a;

    if ( !sqrLength ) {		
        return 0.0f;
    }

    invLength = qyRSqrt( sqrLength );
    r *= invLength;
    g *= invLength;
    b *= invLength;
    a *= invLength;
    return invLength * sqrLength;
} 

//-----------------------------------------------------------------------
QY_INLINE float qyColor::operator[]( const int index ) const
{
	return (&r)[index];
}

//-----------------------------------------------------------------------
QY_INLINE float & qyColor::operator[]( const int index )
{
	return (&r)[index];
}

//-----------------------------------------------------------------------
QY_INLINE bool qyColor::Compare( const qyColor &another ) const
{
	return (r == another.r) && (g == another.g) && (b == another.b) && (a == another.a);
}

//-----------------------------------------------------------------------
QY_INLINE bool qyColor::Compare( const qyColor &another, const float epsilon ) const
{
	if ( fabsf( r - another.r ) > epsilon )
		return false;
	if ( fabsf( g - another.g ) > epsilon )
		return false;
	if ( fabsf( b - another.b ) > epsilon )
		return false;
	if ( fabsf( a - another.a ) > epsilon )
		return false;

	return true;
}


#endif
